/*
 * Copyright (c) 2021-2022 xu
 *
 * HDF is dual licensed: you can use it either under the terms of
 * the GPL, or the BSD license, at your option.
 * See the LICENSE file in the root of this repository for complete details.
 */

#include "temperature_sht31.h"
#include "osal_mem.h"
#include "osal_time.h"
#include "sensor_config_controller.h"
#include "sensor_device_manager.h"
#include "sensor_temperature_driver.h"
#include <securec.h>

#define HDF_LOG_TAG hdf_sensor_temperature

static struct SHT31DrvData *g_sht31DrvData = NULL;

static struct SHT31DrvData *SHT31GetDrvData(void)
{
    return g_sht31DrvData;
}

static uint8_t SHT31CalCRC(uint8_t *data)
{
    uint8_t bit = 0;
    uint8_t crc = 0xFF;
    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
    for (uint8_t dataCounter = 0; dataCounter < 2L; dataCounter++) {
        crc ^= (data[dataCounter]);
        for (bit = 8L; bit > 0; --bit) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ 0x31;
            } else {
                crc = (crc << 1);
            }
        }
    }
    if (crc != data[2L]) {
        HDF_LOGE("ReadSHT31RawData checkCrc fail \n");
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

static uint8_t SHT31ConvertTemperature(uint8_t *data, struct TemperaturemeterData *Temp)
{
    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);

    int16_t unpensateTemp = (int16_t)(SENSOR_DATA_SHIFT_LEFT(data[0], SENSOR_DATA_WIDTH_8_BIT) | data[1]);
    Temp->temperature = -450 + unpensateTemp * 10 * 175 / 65535;
    return HDF_SUCCESS;
}

static int32_t ReadSHT31RawData(struct SensorCfgData *data, struct TemperaturemeterData *Temp)
{
    int32_t ret;
    int i;
    uint8_t rawTemp[6L];

    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);

    ret = ReadSensor(&data->busCfg, SHT31_TEMPERATURE_DATA_ADDR, &rawTemp, sizeof(rawTemp));
    CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");

    ret = SHT31CalCRC(rawTemp);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    ret = SHT31ConvertTemperature(rawTemp, Temp);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    return ret;
}

int32_t ReadSHT31Data(struct SensorCfgData *data)
{
    int32_t ret;
    static int32_t tmp;
    struct TemperaturemeterData temperaturemeterData = {0};
    OsalTimespec time;
    struct SensorReportEvent event;

    (void)memset_s(&time, sizeof(time), 0, sizeof(time));
    (void)memset_s(&event, sizeof(event), 0, sizeof(event));

    if (OsalGetTime(&time) != HDF_SUCCESS) {
        HDF_LOGE("%s: Get time failed", __func__);
        return HDF_FAILURE;
    }
    event.timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT;

    ret = ReadSHT31RawData(data, &temperaturemeterData);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    event.sensorId = data->sensorInfo.sensorId;
    event.mode = SENSOR_WORK_MODE_REALTIME;

    tmp = temperaturemeterData.temperature;

    event.dataLen = sizeof(tmp);
    event.data = (uint8_t *)&tmp;
    ret = ReportSensorEvent(&event);
    return ret;
}

static int32_t InitSHT31(struct SensorCfgData *data)
{
    int32_t ret;

    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
    ret = SetSensorRegCfgArray(&data->busCfg, data->regCfgGroup[SENSOR_INIT_GROUP]);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: SHT31 sensor init config failed", __func__);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

static int32_t DispatchSHT31(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    (void)client;
    (void)cmd;
    (void)data;
    (void)reply;

    return HDF_SUCCESS;
}

int32_t SHT31BindDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);

    struct SHT31DrvData *drvData = (struct SHT31DrvData *)OsalMemCalloc(sizeof(*drvData));
    if (drvData == NULL) {
        HDF_LOGE("%s: Malloc SHT31 drv data fail", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }

    drvData->ioService.Dispatch = DispatchSHT31;
    drvData->device = device;
    device->service = &drvData->ioService;
    g_sht31DrvData = drvData;

    return HDF_SUCCESS;
}

int32_t SHT31InitDriver(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct TemperatureOpsCall ops;

    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
    struct SHT31DrvData *drvData = (struct SHT31DrvData *)device->service;
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);

    drvData->sensorCfg = TemperatureCreateCfgData(device->property);
    if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {
        HDF_LOGD("%s: Creating temperaturecfg failed because detection failed", __func__);
        return HDF_ERR_NOT_SUPPORT;
    }

    ops.Init = NULL;
    ops.ReadData = ReadSHT31Data;
    ret = TemperatureRegisterChipOps(&ops);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Register SHT31 temperature failed", __func__);
        return HDF_FAILURE;
    }

    ret = InitSHT31(drvData->sensorCfg);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Init SHT31 temperature failed", __func__);
        return HDF_FAILURE;
    }

    HDF_LOGI("%s: Init SHT31 temperature success", __func__);
    return HDF_SUCCESS;
}

void SHT31ReleaseDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN(device);

    struct SHT31DrvData *drvData = (struct SHT31DrvData *)device->service;
    CHECK_NULL_PTR_RETURN(drvData);

    if (drvData->sensorCfg != NULL) {
        TemperatureReleaseCfgData(drvData->sensorCfg);
        drvData->sensorCfg = NULL;
    }
    OsalMemFree(drvData);
}

struct HdfDriverEntry g_temperatureSHT31DevEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_SENSOR_TEMPERATURE_SHT31",
    .Bind = SHT31BindDriver,
    .Init = SHT31InitDriver,
    .Release = SHT31ReleaseDriver,
};

HDF_INIT(g_temperatureSHT31DevEntry);